// Date 2008.03.06
// Last modification: 2008.03.25

// Targeted Alpha Therapy with the nuclide pair U230/Th226

// U230 is produced in cyclotrons by proton irradiation of natural Th232.
// With the Range and Stopping Power module

//     1.) we can get the useful dimensions of the target for a proton beam of 33.5 MeV.
//     2.) compute the average cross section
//     3.) calculate the production rate of Th232(p,3n)Pa230 using the average cross section

// than, using the Bateman's analytical solution with Source Termes,
//     4.) compute the production of Pa230 and U230 by a 200 uA proton beam during 50 hours
//     5.) compute the optimal cooling time at which the U230 amount rich a maximum

// With the decay module using a nuclide mixture,
//     6.) calculate the U230 amount after the optimal cooling time (of 27 days)

// with the Packaging & Transport module
//     7.) determine the package type for the transport.



//==================================== functions ========================================

// Measured cross section for Th232(p,3n)Pa230 in mbarn as function of the proton energy
//          XSection = f(pE)
double XSection[18]={0, 0, 90.5, 149.5, 239.1, 352.5, 342.9, 318.7, 315.9, 280.7, 217.9, 169.5, 107.2, 81.8, 80.2, 64.8, 0, 50.1};
double pE[18]={14, 15, 16.4, 17.6, 18.2, 19.9, 21.0, 21.5, 22.5, 23.5, 24.3, 25.2, 26.6, 28.0, 28.6, 31.6, 33.5, 34.0};


double AverageXSection(nuclide Nuclide, double MassThick)
//         AverageXSection
//    Computes the average XSection * MassThickness over Energy from Emin to Emax
//    using a trapezoidal integration rule,
//    Prints the Cross Section Diagram data and
//    returns the average cross section at 33.5 MeV
{
   print("      Diagram:");
   print("Cross Section[mbarn],  and Stopping Power[keV/(g.mm2)]");
   print("Energy [MeV], XSection [mbarn], -dE/dx [keV/(g.mm2)]");

   // Since the cross section did not be measured at 33.5 MeV we have to compute it, here by
   // linear interpolation between 31.6 and 34.0 MeV
   XSection[16] = (XSection[17]-XSection[15])/(pE[17]-pE[15])*(pE[16]-pE[15]) + XSection[15];

   range ProtonsInTh;		// range object for proton in the given Nuclide
   rangeResult RangeResults;	// rangeResult object for increasing proton Energies
   double XSP=0;		// Cross Section Integral
   double AXS;		// Average Cross Section at 33.5 MeV
   double F_Emin;		// function evaluation at interval begin
   double F_Emax;                     // function evaluation at interval end
   int i;			// loop counter
   for(i=1; i<18; i+=1)   // calculate the integral from 15 to 33.5 MeV and the graph from 15 to 34 MeV
   {
      RangeResults = ProtonsInTh.CalculateMono(2,0, pE[i-1],0, Nuclide.Z, Nuclide.Density, 0);
      F_Emin = XSection[i-1] / RangeResults.STotal;
      RangeResults = ProtonsInTh.CalculateMono(2,0, pE[i],0, Nuclide.Z, Nuclide.Density, 0);
      F_Emax = XSection[i] / RangeResults.STotal;
      XSP += (F_Emin + F_Emax) * (pE[i]-pE[i-1]) / 2;
      if (i==16) AXS = XSP/MassThick;
      print("" + pE[i] + ", " + XSection[i] + ", " + format(10*RangeResults.STotal, "0.000"));   //  SP [MeV/g/cm2] = 10*SP [keV/g/mm2] which fits into the XSection scale
   }
   return AXS;		// Return the average cross section at 33.5 MeV
}
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------


int Production(nuclide Pa230, nuclide U230, double R_Pa230, double time)
{
   decayInfo Pa_U;		// decayInfo for the decaying of Pa230 to U230
   int idx;
   for(idx=0; idx<Pa230.DecayInfos; idx+=1)		// Scan the decay products for the U230 daughter
   {
      Pa_U = Pa230.DecayInfo(idx);		// Get the candidat
      if (Pa_U.Daughter == U230.MaterialIndex)	// it is U230 ?
         break;				// exit the loop if U230 is found
   }
   double kPa;	kPa = log(2) / Pa230.Halflife;		// Decay constant of Pa230
   double kU;	kU  = log(2) / U230.Halflife;		// Decay constant of U230
   double BR_PaU;	BR_PaU = Pa_U.BranchingRatio;	// Branching Ration from Pa230 to U230

   print("");
   print("   Diagram:");
   print("Pa230 production trough Th232(p,3n)Pa230");
   print("Time (hour), Pa230 (Bq), U230 (Bq)");

   double APa; double AU;		// Activities of Pa230 and U230 at time t
   double t;				// the time steps
   for (t = 0; t <= time; t += time/10)	// evaluate the Pa and U activities for each time step
   {
      APa = R_Pa230 * (1 - exp(-kPa * t));
      AU = R_Pa230 * kU * kPa * BR_PaU * ( (1-exp(-kPa*t))/kPa - (1-exp(-kU*t))/kU ) / (kU - kPa);
      print("" + (t/3600) + ", " + APa + ", " + AU);
   }
}
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------


int printDaughter(decayResult dkr, int MatIx)
{
   nuclide Daughter; int idx;
   for(idx=1; idx<dkr.Number; idx += 1)
   {
      Daughter = dkr.Nuclide(idx);
      if (Daughter.MaterialIndex == MatIx)
      {
         print(Daughter.IsotopeScreenFormat);
         print("   Activity: " + format(dkr.Activity(idx), "0.000 e+00") + " Bq");
         print("   Mass: " + format(dkr.Mass(idx), "0.000 e+00") + " g");
//         print("   Ingestion Radiotoxicity: " + format(dkr.IngestionRadiotoxicity(idx), "0.000 e+00") + " Sv");       // 28.6 & 141 Sv rather than always 0
//         print("   Dh_dt: " + format(dkr.Dh_dt(idx), "0.000 e+00") + " Sv");                                                      // ??  always 0
         print("   Gamma emission rate: " + format(dkr.G_keV_s(idx), "0.000 e+00") + " keV/s");
         print("   EDC Ingestion: " + format(Daughter.EDCIngestion, "0.000 e+00") + " Sv/Bq");
         print("   Committed effective Dose: " + format(Daughter.EDCIngestion * dkr.Activity(idx), "0.000 e+00") + " Sv");
         print("   ALI for Ingestion: " + format(Daughter.ALIIngestion, "0.000 e+00") + " Bq");
         break;
      }
   }
   return idx;
}
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------


double UnitFactor(string Unit)  // Get the factor corresponding to the Unit of the straggling.
{
   string sUnit[7] = {"A", "m", "um", "mm", "cm", "m", "km"};
   double dUnit[7] = {1e-10, 1e-6, 1e-6,  1e-3, 1e-2, 1, 1e3};
   int i;
   for(i=0; i<7; i+=1)
      if (Unit.IndexOf(sUnit[i])==0 && Unit.Length==sUnit[i].Length) return dUnit[i];
   return 1e-6;   // micro and mu do not work...
}

//============================================ main function ================================================

int main()
{
   print("");
   print("------------------------------------------------------------------------------------------------------------------------------------------------");
   print("       Step 1: Compute and print the minimum required probe dimensions");
   print("------------------------------------------------------------------------------------------------------------------------------------------------");
   print("");

   nuclide Th232;      // At first create the Nuclide object and print some information about it.
   Th232.Create("Th", 232, 0);    // Symbol, Atomic Mass Number, Isomeric state
 
   range pEmax_Th232;       // Create a Range object and print several results about proton irradiation
   rangeResult pEmax_Th232Result;
// Parametrers for CalculateMono():
//     1.) Projectile:		  2 = proton
//     2.) ProjectilIonMatIdx: 	  0, only for other ions (7 for parameter 1.)
//     3.) ProjectileEnergy: 	  33.5
//     4.) ProjectileEnergyUnit:  0 = MeV
//     5.) TargetElement Z:       Th232.Z
//     6.) TargetDensity:         Th232.Density (only used for compounds)
//     7.) TargetPhysicalState:	  0 = Solid.
   pEmax_Th232Result = pEmax_Th232.CalculateMono(2,0, 33.5,0, Th232.Z, Th232.Density,0);

   range pEmin_Th232;       // Create a Range object and print several results about proton irradiation
   rangeResult pEmin_Th232Result;
   pEmin_Th232Result = pEmin_Th232.CalculateMono(2,0, 15,0, Th232.Z, Th232.Density,0);

   double  REmax;		// Range of 33.5 MeV proton in Th [m]
   REmax = pEmax_Th232Result.ProjRange*UnitFactor(pEmax_Th232Result.UnitProjRange);
   double  REmin;		// Range of 15 MeV proton in Th [m]
   REmin = pEmin_Th232Result.ProjRange*UnitFactor(pEmin_Th232Result.UnitProjRange);
   double FoilThickness;   	// useful foil thickness [cm]
   FoilThickness = (REmax - REmin)*100;	// compute the thickness in [cm]

   double EmaxSlat;		// Lateral Straggling by 33.5 MeV protons [m]
// correction  200
   EmaxSlat = (200 + pEmax_Th232Result.StragLat)*UnitFactor(pEmax_Th232Result.UnitStragLat);
   double EminSlat;		// Lateral Straggling by 15 MeV protons [m]
   EminSlat = pEmin_Th232Result.StragLat*UnitFactor(pEmin_Th232Result.UnitStragLat);
   double FoilDiameter;		// Foil diameter in [um]
   FoilDiameter = (EmaxSlat-EminSlat)*1e6;
   print("Since the cross section Th232(p,n3)Pa230 becomes 0 for energies below the 15 Mev threshold,");
   print("   Usefull Probe Thickness: " + format(FoilThickness, "0.000") + " cm");
   print("   Usefull Probe Diameter: " + format(FoilDiameter, "0") + " um + beam diameter");

   print("");
   print("");
   print("------------------------------------------------------------------------------------------------------------------------------------------------");
   print("       Step 2: Calculate the average cross section of Th232(p,3n)Pa230 over the energy range");
   print("------------------------------------------------------------------------------------------------------------------------------------------------");
   print("");
   double MassThickness;	// Usefull Mass Thickness [g/cm2]
   MassThickness = pEmax_Th232Result.MassThickness - pEmin_Th232Result.MassThickness;
   double XSectionAv;	// Average Cross Section [mbarn]
   XSectionAv = AverageXSection(Th232, MassThickness);   // Computes the average cross section over the Energy Range
   print("");
   print("Average Cross Section of Th232(p,3n)Pa230:");
   print("   Usefull Mass Thickness: " + format(MassThickness, "0.000 e+00") + " g/cm2");
   print("   <XSection> = " + format(XSectionAv, "0.00") + " mbarn");


   print("");
   print("");
   print("------------------------------------------------------------------------------------------------------------------------------------------------");
   print("      Step 3: Calculate the Production Rate of Pa230");
   print("------------------------------------------------------------------------------------------------------------------------------------------------");
   print("");
   print("The reaction rate with a beam of 200 uA is:");
   print("       ReactionRate  =  I / e * XSectionAv * 1e-24 * MassThickness / AW * Const_Avogadro [Reactions / sec]");
   double protonCurrent = 200e-6;  // Ampere
   double ReactionRate;
   ReactionRate = protonCurrent / Const_e * XSectionAv * 1e-24  * 1e-3  * MassThickness / Th232.AWR_C12 * Const_Avogadro;
   print("   ReactionRate = " + format(ReactionRate, "0.000 e+00") + " Reactions/sec");
   print("   Proton flux: " + format(protonCurrent / Const_e , "0.000 e+00") + " protons/sec" );

   print("");
   print("");
   print("------------------------------------------------------------------------------------------------------------------------------------------------");
   print("      Step 4: Calculate the Production of Pa230 and U230 over 50 hours");
   print("------------------------------------------------------------------------------------------------------------------------------------------------");
   nuclide Pa230;   
   Pa230.Create("Pa", 230, 0);	// Create the target nuclide
   nuclide U230;
   U230.Create("U", 230, 0);	// Create the daughter nuclide
   decayInfo Pa230_U230;	// decayInfo for Pa230 --> U230 decaying
   int idx;
   for(idx=0; idx<Pa230.DecayInfos; idx+=1)		// Scan all the Pa230.DecayInfos
   {
      Pa230_U230 = Pa230.DecayInfo(idx);		// for Pa230 daughters
      if (Pa230_U230.Daughter == U230.MaterialIndex)	// until the right one is found
	break;				// than abort the loop
   }

   double time;		// irradiation time [sec]
   time = 50 * 3600;		// 50 hours in sec
   print("");
   print("After " + (time/3600) + " hours beaming at " + (protonCurrent*1e6) + " uA, we get:");

   double kPa;	kPa = log(2) / Pa230.Halflife;	// decay constants
   double kU;	kU = log(2) / U230.Halflife;
   double kPaU;	kPaU = kPa * Pa230_U230.BranchingRatio;
   double NPa;	NPa = ReactionRate * (1 - exp(-kPa * time)) / kPa;	// Number of Pa230 atoms
   double NU;	NU = kPaU * ReactionRate / (kU - kPa) * ((1-exp(-kPa*time))/kPa - (1-exp(-kU*time))/kU);	// Number of U230 atoms
   double APa;	APa = NPa * kPa;
   double AU;	AU = NU * kU;
   print("   " + format(NPa, "0.000 e+00") + " atoms Pa230 = " + format(APa * 1e-9, "0.000 e+00") + " GBq     * This is quite good comparing to the 84.1 GBq from the original paper");
   print("   " + format(NU, "0.000 e+00") + " atoms U230 = " + format(AU * 1e-6, "0.000 e+00") + " MBq");

   Production(Pa230, U230, ReactionRate, time);	// Production diagram of Pa230 (and U230) during 50 hours irradiation


   print("");
   print("");
   print("------------------------------------------------------------------------------------------------------------------------------------------------");
   print("      Step 5: compute the optimal cooling time for a maximum production of U230");
   print("------------------------------------------------------------------------------------------------------------------------------------------------");
   print("");
   double tmax;	// time [sec] where U230 reaches the maximum of activity
   tmax = 1  / (kU - kPa) * log(kU/kPa + AU/APa);
   print("Optimal cooling time for maximal U230 production: " + format(tmax/86400, "0.00") + " days");
   print("Neglecting the initial U230 amount: " + format(log(kPa/kU)/(kPa-kU)/86400, "0.00") + " days");

   int tday;
   tday = tmax/86400 + 0.5;   // Rounded optimal Cooling time in [days]
   print("");
   print("");
   print("------------------------------------------------------------------------------------------------------------------------------------------------");
   print("      Step 6: U230 production by decaying a nuclide mixture during " + tday + " days");
   print("------------------------------------------------------------------------------------------------------------------------------------------------");
   print("");
   print("After " + tday + " days cooling time:");
   vnuclide PaU;   // after irradition time, we considere only Pa230 and U230; other nuclides will be neglected
   PaU.Add(Pa230, NPa*kPa, "bq");
   PaU.Add(U230, NU*kU, "bq");
   decayResult dkrPaU;
   dkrPaU = PaU.Decay((NPa*kPa+NU*kU)*8.41e10/(NPa*kPa), "bq", tday, "d", 10, 1, 0.01, "halflife,branching,decay,numbers,mass,activity,activitya,activityb,emission,dose,fission,ingestion,inhalation,isopow,isopowa,isopowb");
   print(dkrPaU.OriginGraph());

   print("");       /// the quantities are about 5% less than the quantities calculated from the application... Why?
   printDaughter(dkrPaU, Pa230.MaterialIndex);	// amount of Pa230
   printDaughter(dkrPaU, U230.MaterialIndex);	// amount of U230

   print("");
   print("");
   print("------------------------------------------------------------------------------------------------------------------------------------------------");
   print("      Step 7: U230 Packaging and Transport");
   print("------------------------------------------------------------------------------------------------------------------------------------------------");
   print("");
   transportSource trSourceU230;			// The Source we have to package for transport
   trSourceU230.Create("U230 2.35 GBq", 0, 0);	// Solid special form, not sealed
   trSourceU230.Add(U230, 2.35e9, "Bq");		// 2.35 GBq of U230
   print(trSourceU230.Name + ", form: " + trSourceU230.Form + ", sealed: " + trSourceU230.IsSealed);
   transportResult trReportU230;			// the Result of the transport calculation
   transport trU230;				// This object creates the Transport Report
   trU230.Add(trSourceU230);			// first add the Source
   trReportU230 = trU230.Calculate();		// then calculate the report
   print("");
   print("   Number of Sources: " + trReportU230.Sources);
   print("");
   int s;
   for(s=0; s<trReportU230.Sources; s+=1)
   {
      print("Totals for Source " + s + ":");
      print("   Mass : " + format(trReportU230.MassTotal(s), "0.000 e+00") + " g");
      print("   Activity: " + format(trReportU230.ActivityTotal(s), "0.000 e+00") + " Bq");
      print("   Heat: " + format(trReportU230.HeatTotal(s), "0.000 e+00") + " W");
      print("   Gamma dose rate at 1 m: " + format(trReportU230.GammaTotal(s)*1e9, "0.000 e+00") + " uSv/h");
      print("   Fissile Uranium ratio: " + format(trReportU230.FissileUranium(s), "0.000"));
      print("   Fissile Plutonium ratio: " + format(trReportU230.FissilePlutonium(s), "0.000"));
      print("   Container Type: " + trReportU230.ContainerType(s));
      print("   Package: " + trReportU230.Package(s));
   }

   print("");
   print("------------------------------------------------------------------------------------------------------------------------------------------------");
}